home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Mode Examples / Scheme-Example.scm < prev    next >
Encoding:
Text File  |  2000-10-30  |  5.6 KB  |  136 lines

  1. ;; Scheme-Example.scm
  2. ;; 
  3. ;; Included in the Alpha distribution as an example of the Scm mode
  4. ;; 
  5. ;; original document can be found at
  6. ;; 
  7. ;; <http://www.cs.rice.edu/~dorai/>
  8. ;; 
  9. ;; reproduced with permission of the author.
  10. ;; 
  11. ;; (c) Dorai Sitaram, 1998-2000  All Rights Reserved
  12.  
  13.  
  14. ;; A clock for infinity
  15. ;; 
  16. ;; The Guile [FSF] procedure alarm provides an interruptable timer mechanism. 
  17. ;; The user can set or reset the alarm for some time units, or stop it.  When
  18. ;; the alarm's timer runs out of this time, it will set off an alarm, whose
  19. ;; consequences are user-settable.  Guile's alarm is not quite the clock of
  20. ;; sec 15.1, but we can modify it easily enough.
  21. ;; 
  22. ;; The alarm's timer is initially stopped or quiescent, ie, it will not set
  23. ;; off an alarm even as time goes by.  To set the alarm's time-to-alarm to be
  24. ;; n seconds, where n is not 0, run (alarm n).  If the timer was already set
  25. ;; (but has not yet set off an alarm), the (alarm n) procedure call will
  26. ;; return the number of seconds remaining from the previous alarm setting.  If
  27. ;; there is no previous alarm setting, (alarm n) returns 0.
  28. ;; 
  29. ;; The procedure call (alarm 0) stops the alarm's timer, ie, the countdown of
  30. ;; time is stopped, the timer becomes quiescent and no alarm will go off. 
  31. ;; (alarm 0) also returns the seconds remaining from a previous alarm setting,
  32. ;; if any.
  33. ;; 
  34. ;; By default, when the alarm's countdown reaches 0, Guile will display a
  35. ;; message on the console and exit.  More useful behavior can be obtained by
  36. ;; using the procedure sigaction, as follows:
  37.  
  38. (sigaction SIGALRM
  39.   (lambda (sig)
  40.     (display "Signal ")
  41.     (display sig)
  42.     (display " raised.  Continuing...")
  43.     (newline)))
  44.  
  45. ;; The first argument SIGALRM (which happens to be 14) identifies to sigaction
  46. ;; that it is the alarm handler that needs setting.9 The second argument is a
  47. ;; unary alarm-handling procedure of the user's choice.  In this example, when
  48. ;; the alarm goes off, the handler displays "Signal 14 raised.  Continuing..." 
  49. ;; on the console without exiting Scheme.  (The 14 is the SIGALRM value that
  50. ;; the alarm will pass to its handler.  Don't worry about it now.)
  51. ;; 
  52. ;; From our point of view, this simple timer mechanism poses one problem.  A
  53. ;; return value of 0 from a call to the procedure alarm is ambiguous: It could
  54. ;; either mean that the alarm was quiescent, or that it was just about to run
  55. ;; out of time.  We could resolve this ambiguity if we could include
  56. ;; ``*infinity*'' in the alarm arithmetic.  In other words, we would like a
  57. ;; clock that works almost like alarm, except that a quiescent clock is one
  58. ;; with *infinity* seconds.  This will make many things natural, viz,
  59. ;; 
  60. ;; (1) (clock n) on a quiescent clock returns *infinity*, not 0.
  61. ;; 
  62. ;; (2) To stop the clock, call (clock *infinity*), not (clock 0).
  63. ;; 
  64. ;; (3) (clock 0) is equivalent to setting the clock to an infinitesimally
  65. ;; small amount of time, viz, to cause it to raise an alarm instantaneously.
  66. ;; 
  67. ;; In Guile, we can define *infinity* as the following ``number'':
  68.  
  69. (define *infinity* (/ 1 0))
  70.  
  71. ;; We can define clock in terms of alarm.
  72.  
  73. (define clock
  74.   (let ((stopped? #t)
  75.         (clock-interrupt-handler
  76.          (lambda () (error "Clock interrupt!"))))
  77.     (let ((generate-clock-interrupt
  78.            (lambda ()
  79.              (set! stopped? #t)
  80.              (clock-interrupt-handler))))
  81.       (sigaction SIGALRM
  82.                  (lambda (sig) (generate-clock-interrupt)))
  83.       (lambda (msg val)
  84.         (case msg
  85.           ((set-handler)
  86.            (set! clock-interrupt-handler val))
  87.           ((set)
  88.            (cond ((= val *infinity*)
  89.                   ;This is equivalent to stopping the clock.
  90.                   ;This is almost equivalent to (alarm 0), except
  91.                   ;that if the clock is already stopped,
  92.                   ;return *infinity*.
  93.  
  94.                   (let ((time-remaining (alarm 0)))
  95.                     (if stopped? *infinity*
  96.                         (begin (set! stopped? #t) time-remaining))))
  97.  
  98.                  ((= val 0)
  99.                   ;This is equivalent to setting the alarm to
  100.                   ;go off immediately.  This is almost equivalent
  101.                   ;to (alarm 0), except you force the alarm
  102.                   ;handler to run.
  103.  
  104.                   (let ((time-remaining (alarm 0)))
  105.                     (if stopped?
  106.                         (begin (generate-clock-interrupt) *infinity*)
  107.                         (begin (generate-clock-interrupt) time-remaining))))
  108.  
  109.                  (else
  110.                   ;This is equivalent to (alarm n) for n != 0.
  111.                   ;Just remember to return *infinity* if the
  112.                   ;clock was previously quiescent.
  113.  
  114.                   (let ((time-remaining (alarm val)))
  115.                     (if stopped?
  116.                         (begin (set! stopped? #f) *infinity*)
  117.                         time-remaining))))))))))
  118.  
  119. ;; The clock procedure uses three internal state variables:
  120. ;; 
  121. ;; (1) stopped?, to describe if the clock is stopped;
  122. ;; 
  123. ;; (2) clock-interrupt-handler, which is a thunk describing the user-specified
  124. ;; part of the alarm-handling action; and
  125. ;; 
  126. ;; (3) generate-clock-interrupt, another thunk which will set stopped?  to
  127. ;; false before running the user-specified alarm handler.
  128. ;; 
  129. ;; The clock procedure takes two arguments.  If the first argument is
  130. ;; set-handler, it uses the second argument as the alarm handler.
  131. ;; 
  132. ;; If the first argument is set, it sets the time-to-alarm to the second
  133. ;; argument, returning the time remaining from a previous setting.  The code
  134. ;; treats 0, *infinity* and other values for time differently so that the user
  135. ;; gets a mathematically transparent interface to alarm.
  136.